using System;
using System.Threading;
using System.Threading.Tasks;
using Dapper;
using Microsoft.Extensions.Options;
using MySql.Data.MySqlClient;
using RequestLog.Extension.Model;
using RequestLog.Internal;
using RequestLog.Persistence;
using RequestLog.Serialize;

namespace RequestLog.MySql
{
    /// <summary>
    /// 
    /// </summary>
    public class RequestLogRepository : IRequestLogRepository
    {
        private readonly MySqlOptions _options;
        private IJsonProvider _jsonProvider;
        private readonly IStorageInitializer _storageInitializer;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="storageInitializer"></param>
        /// <param name="options"></param>
        /// <param name="jsonProvider"></param>
        public RequestLogRepository(IStorageInitializer storageInitializer, IOptions<MySqlOptions> options,
            IJsonProvider jsonProvider)
        {
            this._storageInitializer = storageInitializer;
            this._options = options.Value;
            this._jsonProvider = jsonProvider;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="requestData"></param>
        /// <returns></returns>
        public async Task Record(RequestData requestData)
        {
            await CheckTable();
            var sql =
                $"INSERT INTO `{_storageInitializer.GetTableName()}`(`id`,`unique`,`name`,`request_url`,`headers`,`protocol`,`scheme`,`message`,`timestamp`,`state`,`response`,`duration`,`extend`) VALUES(@id,@unique,@name,@request_url,@headers,@protocol,@scheme,@message,@timestamp,@state,@response,@duration,@extend);";
            using (var connection = new MySqlConnection(_options.ConnectionString))
            {
                try
                {
                    string id = SnowflakeId.Default().NextId().ToString();
                    await connection.ExecuteAsync(sql, new
                    {
                        id = id,
                        unique = requestData.Unique,
                        name = requestData.Name,
                        request_url = requestData.RequestUrl,
                        headers = GetString(requestData.Headers),
                        protocol = requestData.Protocol,
                        scheme = requestData.Scheme,
                        message = GetString(requestData.Message),
                        timestamp = requestData.Timestamp,
                        state = requestData.IsError ? 0 : 1,
                        response = GetString(requestData.Response),
                        duration = requestData.Duration,
                        extend = GetString(requestData.Extend)
                    });
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            }
        }

        /// <summary>
        /// 得到Json
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private string GetString(object data)
        {
            if (data == null)
            {
                return "";
            }

            if (data.GetType().IsClass && !(data is string))
            {
                return this._jsonProvider.Serializer(data);
            }

            return data.ToString();
        }

        /// <summary>
        /// 检查表
        /// </summary>
        /// <returns></returns>
        private async Task CheckTable()
        {
            if ((_options.Rules == Rules.Year && MySqlOptionsExtension.LastExecTime.Date.Year == DateTime.Now.Year) ||
                (_options.Rules == Rules.Month &&
                 MySqlOptionsExtension.LastExecTime.Date.Month == DateTime.Now.Month) ||
                (_options.Rules == Rules.Day && MySqlOptionsExtension.LastExecTime.Date.Day == DateTime.Now.Day))
            {
                return;
            }

            CancellationToken cancellationToken = new CancellationToken();
            await _storageInitializer.InitializeAsync(cancellationToken);
        }
    }
}